import random

from flask import current_app, jsonify, make_response, request
from . import api
from app.utils.captcha.captcha import captcha
from app import redis, constants
from app.utils.response_code import RET
# from ..libs.yunliantong.SendMessage import SmsSingleton
from ..utils.ronglianyun.SendMessage import SmsSingleton
from ..models import User


@api.route('/image_codes/<image_code_id>')
def get_image_code(image_code_id):
    """
    获取图片验证码
    :param image_code_id: 图片验证码编号
    :return: 正常情况验证码图片，异常返回错误json数据
    """
    # 获取参数
    # 生成验证码图片 name 名字, text 真实文本, image_dat 图片数据
    name, text, image_data = captcha.generate_captcha()

    """
    将验证码真实值和编号保存到redis, 设置有效期
    redis常见字符类型：字符串、列表、哈希(键值对)、set

    单条维护记录，采用字符串
    "image_code_编号1"："真实值"
    "image_code_编号2"："真实值"
    redis.set(f"image_code_{image_code_id}", text)  保存数据
    redis.expire(f"image_code_{image_code_id}", constants.IMAGE_CODE_REDIS_EXPIRES) 设置有效期
    """
    # 保存图表验证码有redis中，并设置有效期（注意第二个参数是过期时间）
    try:
        redis.setex(f"image_code_{image_code_id}", constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        # 将错误信息记录到日志
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="redis保存图片验证码信息失败")

    # 设置响应头为图片
    resp = make_response(image_data)
    resp.headers['Content-Type'] = 'image/jpg'

    # 返回验证码图片
    return resp


@api.route("/sms_codes/<re(r'1[23456789]\d{9}'):mobile>")
def get_sms_code(mobile):
    """
    获取短信验证码, get请求参数 sms_codes/17712345678？
    前端需要传递过来：图片验证码id、图片验证码id、手机号码，
    手机号码也需要保存到redis，使用手机号码作为验证码id
    :param mobile: 手机号码
    :return:
    """
    # 获取参数
    image_code_id = request.args.get('image_code_id')  # 图片验证码id
    image_code = request.args.get("image_code")  # 图片验证码

    # 校验参数
    if not all([image_code, image_code_id]):
        # 执行这里表示参数不完整（缺少参数）
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # 从redis中取出真实的图片验证码
    try:
        real_image_code = redis.get(f"image_code_{image_code_id}")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="redis数据库异常")

    # 判断图片验证码是否过期
    if real_image_code is None:
        return jsonify(errno=RET.NODATA, errmsg="图片验证码失效")

    # 删除redis中的图片验证码。用于防止用户使用同一个验证码验证多次的情况
    try:
        redis.delete(f"image_code_{image_code_id}")
    except Exception as e:
        current_app.logger.error(e)

    # 图片验证码未过期则与用户填写的值进行对比， lower() 表示转换成小写比较
    # real_image_code.decode('utf-8') 将字节序列 b'sv8t' 解码为相应的字符串 'sv8t'。
    if real_image_code.decode('utf-8').lower() != image_code.lower():
        # 表示用户填写错误
        return jsonify(errno=RET.DATAERR, errmsg="图片验证码输入错误")

    try:
        send_flay = redis.get(f'sms_code_{mobile}')
    except Exception as e:
        current_app.logger.error(e)
    else:
        if send_flay is not None:
            return jsonify(errno=RET.REQERR, errmsg="请求过于频繁, 请60s后重试")

    # 判断手机号是否存在, 如果存在则不能注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
    else:
        if user is not None:
            # 表示手机号码已经存在
            return jsonify(errno=RET.DATAEXIST, errmsg="手机号码已经存在")

    # 如果手机号码未注册，则生成注册时短信验证码, 四位数字验证码
    sms_code = random.randint(1000, 9999)

    # 在redis中保存生成的短信验证码格式：   sms_code_17712344321:3435
    try:
        redis.setex(f'sms_code_{mobile}', constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="保存短信验证码异常")

    # 发送短信
    # datas = ('1234', '5')  # 例如：验证码是1234，5分钟内有效
    # constants.SMS_CODE_REDIS_EXPIRES/60 将秒换算成分钟
    try:
        sms_singleton = SmsSingleton()
        result = sms_singleton.send_message('1', mobile, (f"{sms_code}", f"{constants.SMS_CODE_REDIS_EXPIRES / 60}"))
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="短信发送异常")

    # 发送短信返回值判断是否成功
    if result == 0:
        # 发送成功
        return jsonify(errno=RET.OK, errmsg="短信发送成功")
    else:
        # 发送失败
        return jsonify(errno=RET.THIRDERR, errmsg="短信发送失败")